package com.hmdp.controller;

import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.UserInfo;
import com.hmdp.service.IUserInfoService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @Resource
    private IUserInfoService userInfoService;

    /**
     * 发送手机验证码
     *      -- 基于 Session 实现的短信验证码发送给
     *      -- 首先某一个客户端提交一个手机号过来
     *      -- 后端要给前端返回一个验证码 验证码是通过短信的方式发送给用户的
     *      -- 接着用户会通过提交手机号和验证码来请求登录
     *      -- 拿着时候浏览器就要判断验证码是否与发送的时候一致
     *      -- 每个线程之间都是独立的 后端又怎么拿到之前的验证码呢 ？ ThreadLocal ??? 肯定不是
     *      -- session 因为尽管不是一次请求 但是是一个会话内的 他们之间会有一个 session 是共享的 而且这个 session 是每个客户端之间独有的
     *      -- 所以我们使用 session 存储之前的 验证码 键值的话不用专门设置
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) throws Exception {
        // 发送短信验证码并保存验证码
        log.info("发送短信验证码：{}",phone);
        return userService.sendCode(phone,session);
    }

    /**
     * 登录功能
     *      -- 这个登录功能是基于 session 实现的
     *      -- 首先判断下手机号格式
     *      -- 接着是验证码 首先根据之前存入的键值 code 从 session 中取出保存好的验证码的值 cacheCode
     *      -- 判断这个验证码是否为空以及是否等于传过来的 code
     *      -- 都成功的话根据手机号从数据库中查出 user 对象
     *      -- 没查出来的话就创建一个新的 保存到数据库
     *      -- 这个是 session 技术 你要把 user 存进 session 中 方便拦截器里取出它然后存进 ThreadLocal
     *      -- 拦截器也是根据 session 中有没有 user 对象来判断请求登录没有的
     *      -- 直接返回 ok 不用携带凭证 因为这里是 session
     *      -- 用 Redis 做：
     *          -- 这里首先一个问题就是所有的用户都往同一个 Redis 里面存 如果都用 code 做 key 那会冲突很多
     *          -- 为了一个手机号一个 key 我们用手机号做 key
     *          -- 所以存验证码解决了 存用户怎么解决 ??? 用户用什么数据类型存 ??? 用什么 key 呢 ???
     *              -- 用 hash 存 不仅占用空间少 而且支持对单个属性的增删改查
     *              -- 用一个 UUID 作为 key 并且把他返回给前端 这里不用 手机号是因为手机号太容易泄露了
     * @param loginForm 登录参数，包含手机号、验证码；或者手机号、密码
     */
    @PostMapping("/login")
    public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
        // 实现登录功能
        log.info("用户登录：{}",loginForm);
        return userService.login(loginForm,session);
    }

    /**
     * 登出功能
     * @return 无
     */
    @PostMapping("/logout")
    public Result logout(){
        // 实现登出功能
        log.info("用户登出...");
        return Result.ok();
    }

    @GetMapping("/me")
    public Result me(){
        // 获取当前登录的用户并返回
        log.info("获取当前登录的用户...");
        UserDTO userDTO = UserHolder.getUser();
        return Result.ok(userDTO);
    }

    @GetMapping("/info/{id}")
    public Result info(@PathVariable("id") Long userId){
        // 查询详情
        UserInfo info = userInfoService.getById(userId);
        if (info == null) {
            // 没有详情，应该是第一次查看详情
            return Result.ok();
        }
        info.setCreateTime(null);
        info.setUpdateTime(null);
        // 返回
        return Result.ok(info);
    }
}
